package com.seguridad.txwrapping.tester;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Date;
import java.util.Random;

import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;

import org.w3c.dom.DOMException;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class WSSWSimpleAncestryTester extends WSSWTester {

	public WSSWSimpleAncestryTester(URL endpoint, String validMessagePath, String elementName) {
		super(endpoint, validMessagePath, elementName);
	}

	@Override
	protected String sampleWrapped() {
		logger.debug("########## SAMPLE ANCESTRY");
		String hash = null;
		SOAPConnection connection = null;
		InputStream is = null;
		try {
			is = new FileInputStream(getValidMessagePath());
			SOAPConnectionFactory sfc = SOAPConnectionFactory.newInstance();
			connection = sfc.createConnection();
			
			MessageFactory mf = MessageFactory.newInstance();
			SOAPMessage sm = mf.createMessage(null, is);
			
			// 1 - Buscar el elemento a wrappear
			Node originalNode = searchNodeToWrap(sm);
			// 2 - Crear el wrapper con una copia del elemento
			addTheWrappedElement(sm, originalNode);
			// 3 - Modificar los valores del elemento original
			changeOriginalValues(originalNode);
			// 4 - Modificar el id del elemento original
			changeIdOfElement(originalNode);

			if(logger.isDebugEnabled()){
				logger.debug("REQUEST");
				ByteArrayOutputStream baos = new ByteArrayOutputStream();
				sm.writeTo(baos);
				logger.debug(baos.toString());
			}
			
			SOAPMessage response = connection.call(sm, getEndpoint());
			
			if(logger.isDebugEnabled()){
				logger.debug("RESPONSE");
				ByteArrayOutputStream baos = new ByteArrayOutputStream();
				response.writeTo(baos);
				logger.debug(baos.toString());
			}
			
			hash = hashBody(response);
			
		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			try {
				if(connection != null) {connection.close();}
				if(is != null) {is.close();}
			} catch (SOAPException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return hash;
	}

	private void changeIdOfElement(Node node) {
		Node attr = node.getAttributes().getNamedItem("ID");
		
		if(attr == null){
			attr = node.getAttributes().getNamedItem("Id");
		}
		
		attr.setNodeValue(Long.toString(new Date().getTime()));
	}

	private void changeOriginalValues(Node node) {
		NodeList childs = node.getChildNodes();
		Random random = new Random(new Date().getTime());
		
		for (int i = 0; i < childs.getLength(); i++) {
			Node child = childs.item(i);
			
			if(child.getTextContent() != null){
				String text = child.getTextContent().trim().replaceAll(">\\s+<", "><").replaceAll("^<\\?xml[^?]+\\?>", "");
				if(!text.equals("")){		
					child.setTextContent(Integer.toString(random.nextInt()));
				}
			}
		}		
	}

	private void addTheWrappedElement(SOAPMessage sm, Node node) {
		try {
			Node clonnedNode = node.cloneNode(true);
				
			String nsPrefix = sm.getSOAPPart().getEnvelope().getPrefix();
			Element wrapNode = sm.getSOAPPart().createElement("Wrapper");
			wrapNode.setAttribute(nsPrefix + ":mustUnderstand", "0");
			wrapNode.setAttribute(nsPrefix + ":role", ".../none");
			wrapNode.appendChild(clonnedNode);
		
			sm.getSOAPHeader().appendChild(wrapNode);
		} catch (DOMException e) {
			e.printStackTrace();
		} catch (SOAPException e) {
			e.printStackTrace();
		}
	}

}
